package com.gitee.wsl.common.draw.gesture

import android.content.Context
import android.graphics.PointF
import android.widget.OverScroller
import com.gitee.wsl.common.draw.gesture.computator.ChartCommutator
import com.gitee.wsl.common.draw.area.Viewport
import timber.log.Timber

/**
 * Encapsulates scrolling functionality.
 */
class ChartScroller(context: Context,val commutator: ChartCommutator) {
    private val scrollerStartViewport = Viewport() // Used only for zooms and flings
    private val surfaceSizeBuffer = PointF() // Used for scroll and flings
    private val scroller: OverScroller = OverScroller(context)

    fun startScroll(): Boolean {
        scroller.abortAnimation()
        scrollerStartViewport.set(commutator.currentViewport)
        Timber.d("scroll start $scrollerStartViewport")
        return true
    }

    fun scroll_old(distanceX: Float, distanceY: Float, scrollResult: ScrollResult): Boolean {
        // Scrolling uses math based on the viewport (as opposed to math using pixels). Pixel offset is the offset in
        // screen pixels, while viewport offset is the offset within the current viewport. For additional
        // information on
        // surface sizes and pixel offsets, see the docs for {@link computeScrollSurfaceSize()}. For additional
        // information about the viewport, see the comments for {@link mCurrentViewport}.
        val maxViewport = commutator.maximumViewport
        val visibleViewport = commutator.visibleViewport
        val currentViewport = commutator.currentViewport
        val contentRect = commutator.contentRectMinusAllMargins
        val canScrollLeft = currentViewport.left > maxViewport.left
        val canScrollRight = currentViewport.right < maxViewport.right
        val canScrollTop = currentViewport.top < maxViewport.top
        val canScrollBottom = currentViewport.bottom > maxViewport.bottom

        val canScrollX = (canScrollLeft && distanceX <= 0) || (canScrollRight && distanceX >= 0)
        val canScrollY = (canScrollTop && distanceY <= 0) || (canScrollBottom && distanceY >= 0)

        Timber.d("scroll ing distanceX:$distanceX,distanceY:$distanceY  canScrollX:$canScrollX  canScrollY:$canScrollY ")
        if (canScrollX || canScrollY) {
            commutator.computeScrollSurfaceSize(surfaceSizeBuffer)
            val viewportOffsetX = distanceX * visibleViewport.width / contentRect.width()
            val viewportOffsetY = distanceY * visibleViewport.height / contentRect.height()
            commutator.setViewportTopLeft(currentViewport.left + viewportOffsetX, currentViewport.top + viewportOffsetY)
        }
        scrollResult.canScrollX = canScrollX
        scrollResult.canScrollY = canScrollY
        return canScrollX || canScrollY
    }

    fun scroll(distanceX: Float, distanceY: Float, scrollResult: ScrollResult): Boolean {
        // Scrolling uses math based on the viewport (as opposed to math using pixels). Pixel offset is the offset in
        // screen pixels, while viewport offset is the offset within the current viewport. For additional
        // information on
        // surface sizes and pixel offsets, see the docs for {@link computeScrollSurfaceSize()}. For additional
        // information about the viewport, see the comments for {@link mCurrentViewport}.
        val maxViewport = commutator.maximumViewport

        val currentViewport = commutator.currentViewport

        val canScrollLeft = currentViewport.left > maxViewport.left
        val canScrollRight = currentViewport.right < maxViewport.right
        val canScrollTop = currentViewport.top > maxViewport.top
        val canScrollBottom = currentViewport.bottom < maxViewport.bottom

        val realDistX = distanceX //* commutator.scaleValueX
        val realDistY = distanceY //* commutator.scaleValueY

        val canScrollX = (canScrollLeft && realDistX <= 0) || (canScrollRight && realDistX >= 0)
        val canScrollY = (canScrollTop && realDistY <= 0) || (canScrollBottom && realDistY >= 0)

        Timber.d("scroll ing distanceX:$realDistX,distanceY:$realDistY  canScrollX:$canScrollX  canScrollY:$canScrollY ")
        if (canScrollX || canScrollY) {
           commutator.setViewportTopLeft(currentViewport.left + realDistX, currentViewport.top + realDistY)
        }
        scrollResult.canScrollX = canScrollX
        scrollResult.canScrollY = canScrollY
        return canScrollX || canScrollY
    }

    fun computeScrollOffset(): Boolean {
        /*if (scroller.computeScrollOffset()) {
            // The scroller isn't finished, meaning a fling or programmatic pan operation is
            // currently active.
            val maxViewport = commutator.maximumViewport
            commutator.computeScrollSurfaceSize(surfaceSizeBuffer)
            val currXRange = maxViewport.left + maxViewport.width * scroller.currX / surfaceSizeBuffer.x
            val currYRange = maxViewport.top + maxViewport.height * scroller.currY / surfaceSizeBuffer.y
            commutator.setViewportTopLeft(currXRange, currYRange)
            return true
        }*/
        return false
    }

    fun fling(velocityX: Int, velocityY: Int): Boolean {
        // Flings use math in pixels (as opposed to math based on the viewport).
        commutator.computeScrollSurfaceSize(surfaceSizeBuffer)
        scrollerStartViewport.set(commutator.currentViewport)
        val startX = (surfaceSizeBuffer.x * (scrollerStartViewport.left - commutator.maximumViewport.left) / commutator.maximumViewport.width).toInt()
        val startY = (surfaceSizeBuffer.y * (scrollerStartViewport.top - commutator.maximumViewport.top ) / commutator.maximumViewport.height).toInt()

        // TODO probably should be mScroller.forceFinish but ScrollerCompat doesn't have that method.
        scroller.abortAnimation()
        val width = commutator.contentRectMinusAllMargins.width()
        val height = commutator.contentRectMinusAllMargins.height()
        scroller.fling(startX, startY, velocityX, velocityY, 0, (surfaceSizeBuffer.x - width + 1).toInt(), 0, (surfaceSizeBuffer.y - height + 1).toInt())
        Timber.d("scroll fling  velocityX:$velocityX, velocityY:$velocityY")
        return true
    }

    class ScrollResult {
        @JvmField
        var canScrollX = false
        @JvmField
        var canScrollY = false
    }
}

enum class ContainerScrollType {
    HORIZONTAL, VERTICAL, NONE , ALL
}